package com.wechat.ferry.service.impl;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.wechat.ferry.config.WeChatFerryProperties;
import com.wechat.ferry.service.WeChatDllService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class ScriptRunner {

    @Autowired
    private WeChatFerryProperties weChatFerryProperties;
    @Autowired
    private WeChatDllService weChatDllService;

    public void restartApplication() throws Exception {
        // 1. 准备参数
        String scriptFolderPath = weChatFerryProperties.getScriptFolder();
        String appName = "wechat-ferry-mvn-39.2.4.jar";
        String jarPath = weChatFerryProperties.getJarPath() + "\\" + appName;
        String logDir = scriptFolderPath + "\\" + "logs";
        String javaOpts = "-Dfile.encoding=UTF-8 -Xmx512m";

        log.info("正在准备重启参数...");
        log.info("应用名称: {}", appName);
        log.info("JAR路径: {}", jarPath);
        log.info("日志目录: {}", logDir);

        // 2. 生成增强版批处理脚本
        log.info("正在生成重启脚本...");
        Path scriptPath = generateKillAndRestartScript(appName, jarPath, logDir, javaOpts);
        log.info("脚本生成成功: {}", scriptPath);

        // 3. 通过独立进程执行脚本
        log.info("正在启动独立进程执行脚本...");
        ProcessBuilder pb = new ProcessBuilder(
                "cmd.exe", "/c",
                "start", "\"WeChatRestarter_\"" + IdUtil.getSnowflakeNextId(),
                "cmd.exe", "/c",
                "\"" + scriptPath.toString() + "\""
        );
        pb.inheritIO();
        Process process = pb.start();
        log.info("重启进程已启动");

        // 4. 当前进程退出
        System.exit(0);
    }


    public static Path generateKillAndRestartScript(String appName, String jarPath,
                                                    String logDir, String javaOpts) throws IOException {
        // 获取当前日期
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        String currentDate = dateFormat.format(new Date());

        // 构造日志文件名
        String logFileName = String.format("wechat_restart_%s_%s.log", currentDate, DateUtil.format(LocalDateTime.now(), "HHmmssSSS"));
        String logFilePath = logDir + "\\" + logFileName;

        // 构建批处理脚本内容
        StringBuilder script = new StringBuilder();
        script.append("@echo off\r\n");
        script.append("chcp 65001 > nul\r\n");
        script.append("setlocal enabledelayedexpansion\r\n");

        // 参数设置
        script.append("set APP_NAME=").append(appName).append("\r\n");
        script.append("echo APP_NAME=").append(appName).append("\r\n");
        script.append("set JAR_PATH=").append(jarPath).append("\r\n");
        script.append("echo JAR_PATH=").append(jarPath).append("\r\n");
        script.append("set LOG_FILE=").append(logFilePath).append("\r\n");
        script.append("echo LOG_FILE=").append(logFilePath).append("\r\n");
        script.append("set JAVA_OPTS=").append(javaOpts).append("\r\n");
        script.append("echo JAVA_OPTS=").append(javaOpts).append("\r\n");

        // 创建日志目录
        script.append("if not exist \"").append(logDir).append("\" mkdir \"").append(logDir).append("\"\r\n");

        // 记录启动信息（控制台和日志）
        script.append("echo [%date% %time%] 开始重启流程\r\n");

        // 增强版进程终止（三层保障）
        script.append(":KILL_LOOP\r\n");
        script.append("echo [%time%] 正在终止旧进程...\r\n");
        script.append("echo [%time%] 正在终止旧进程... >> \"%LOG_FILE%\"\r\n");

        // 先检查进程是否存在，只有存在时才尝试终止
        script.append(":: 检查并终止进程\r\n");
        script.append("tasklist /FI \"IMAGENAME eq java.exe\" /FI \"WINDOWTITLE eq %APP_NAME%\" 2>nul | find /i \"%APP_NAME%\" >nul\r\n");
        script.append("if %errorlevel% equ 0 (\r\n");
        script.append("    echo [%time%] 正在终止进程... >> \"%LOG_FILE%\"\r\n");
        script.append("    taskkill /F /IM java.exe /FI \"WINDOWTITLE eq %APP_NAME%\" >> \"%LOG_FILE%\" 2>&1\r\n");
        script.append("    timeout /t 2 >nul\r\n");
        script.append("    :: 使用WMIC确保终止\r\n");
        script.append("    wmic process where \"commandline like '%%").append(jarPath.replace("\\", "\\\\")).append("%%'\" delete >> \"%LOG_FILE%\" 2>&1\r\n");
        script.append("    timeout /t 3 >nul\r\n");
        script.append("    :: 验证是否终止成功\r\n");
        script.append("    tasklist /FI \"IMAGENAME eq java.exe\" /FI \"WINDOWTITLE eq %APP_NAME%\" 2>nul | find /i \"%APP_NAME%\" >nul\r\n");
        script.append("    if %errorlevel% equ 0 (\r\n");
        script.append("        echo [%time%] 警告: 进程终止失败 >> \"%LOG_FILE%\"\r\n");
        script.append("    ) else (\r\n");
        script.append("        echo [%time%] 进程已成功终止 >> \"%LOG_FILE%\"\r\n");
        script.append("    )\r\n");
        script.append(") else (\r\n");
        script.append("    echo [%time%] 没有找到需要终止的进程 >> \"%LOG_FILE%\"\r\n");
        script.append(")\r\n");

//        script.append("taskkill /F /IM java.exe /FI \"WINDOWTITLE eq %APP_NAME%\" >> \"%LOG_FILE%\" 2>&1\r\n");
//        script.append("wmic process where \"commandline like '%%").append(jarPath.replace("\\", "\\\\")).append("%%'\" delete >> \"%LOG_FILE%\" 2>&1\r\n");
//        script.append("timeout /t 5 >nul\r\n");

        // 检查是否终止成功
        script.append("tasklist /FI \"IMAGENAME eq java.exe\" | findstr /i \"").append(appName).append("\" >nul\r\n");
        script.append("if %errorlevel% equ 0 (\r\n");
        script.append("   echo [%time%] 进程仍在运行，重试终止...\r\n");
        script.append("   echo [%time%] 进程仍在运行，重试终止... >> \"%LOG_FILE%\"\r\n");
        script.append("   goto KILL_LOOP\r\n");
        script.append(")\r\n");


        // 启动新进程
        script.append("echo [%time%] 正在启动新进程...\r\n");
        script.append("echo [%time%] 正在启动新进程... >> \"%LOG_FILE%\"\r\n");
        script.append("start \"\" /B cmd /c \"java.exe %JAVA_OPTS% -jar \"").append(jarPath).append("\" >> \"%LOG_FILE%\" 2>&1\"\r\n");
        script.append("   echo [%time%] 启动脚本调用完成，日志输出到: \"%LOG_FILE%\"\r\n");
        // 验证启动
        script.append("timeout /t 10 >nul\r\n");
        script.append("tasklist /FI \"IMAGENAME eq java.exe\" | findstr /i \"").append(jarPath).append("\" >nul\r\n");
        script.append("if %errorlevel% equ 0 (\r\n");
        script.append("   echo [%time%] 重启成功！PID: \r\n");
        script.append("   echo [%time%] 重启成功！PID: >> \"%LOG_FILE%\"\r\n");
        script.append("   tasklist /FI \"IMAGENAME eq java.exe\" | findstr /i \"").append(jarPath).append("\" >> \"%LOG_FILE%\"\r\n");
        script.append("   tasklist /FI \"IMAGENAME eq java.exe\" | findstr /i \"").append(jarPath).append("\" \r\n");
        script.append(")\r\n");
        script.append("   echo [%time%] 启动完成，日志输出到: \"%LOG_FILE%\"\r\n");
        script.append("exit /b 0\r\n");

        // 写入临时文件
        Path scriptPath = Files.createTempFile("restart_" + IdUtil.getSnowflakeNextId(), ".bat");
        Files.write(scriptPath, script.toString().getBytes(StandardCharsets.UTF_8));
        scriptPath.toFile().deleteOnExit();
        return scriptPath;
    }

    /**
     * 执行重启脚本
     *
     * @throws Exception
     */
    @SneakyThrows
    public void runRestartScript() {
        restartApplication();
    }


    /**
     * 每两分钟执行一次
     */
    @Scheduled(cron = "0 0/2 * * * ? ")
    public void scanRobotStatus() {
        log.info("定时任务检测机器人状态开始...");
        try {
            Boolean loginStatus = weChatDllService.loginStatus();
            log.info("定时任务检测机器人状态结束,机器人状态:{}", Boolean.FALSE.equals(loginStatus) ? "未启动" : "启动中");
            if (Boolean.FALSE.equals(loginStatus)) {
                log.info("定时任务检测机器人状态异常,即将重启机器人...");
                runRestartScript();
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.info("定时任务检测机器人状态异常,即将重启机器人...");
            runRestartScript();
        }
    }
}